import os
import sys

from PyQt5.QtWidgets import (
    QApplication, QWidget, QLabel, QLineEdit, QPushButton, QTextEdit,
    QVBoxLayout, QHBoxLayout, QFileDialog, QGraphicsView, QGraphicsScene,
    QMessageBox, QScrollArea, QSplitter, QSizePolicy, QTabWidget
)
from PyQt5.QtGui import QPixmap, QFont, QIcon
from PyQt5.QtCore import Qt, QRectF
from .analyzer import analyze_function


class PathAnalyzerGUI(QWidget):
    """基本路径集生成工具的GUI界面"""

    def __init__(self):
        super().__init__()
        self.setWindowTitle("基本路径集生成工具 - BPSAGT")
        self.setGeometry(100, 100, 1000, 700)
        self.setMinimumSize(800, 600)  # 设置最小窗口尺寸

        # 尝试设置窗口图标
        try:
            self.setWindowIcon(QIcon('icon.png'))
        except:
            pass

        self.setStyleSheet("""
            QWidget {
                background-color: #f8f9fa;
                font-family: "Segoe UI", sans-serif;
                font-size: 14px;
            }
            QLabel {
                font-weight: bold;
                color: #343a40;
            }
            QLineEdit, QTextEdit, QComboBox {
                padding: 6px;
                border: 1px solid #ced4da;
                border-radius: 4px;
            }
            QPushButton {
                background-color: #007bff;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #0056b3;
            }
            QTextEdit {
                background-color: #ffffff;
                border: 1px solid #ced4da;
            }
        """)

        self.installEventFilter(self)  # 安装事件过滤器以支持快捷键缩放
        self.init_ui()

    def zoom_in(self):
        """放大图像"""
        self.cfg_view.scale(1.2, 1.2)

    def zoom_out(self):
        """缩小图像"""
        self.cfg_view.scale(1 / 1.2, 1 / 1.2)

    def reset_view(self):
        """重置视图缩放"""
        self.cfg_view.resetTransform()
        self.cfg_view.fitInView(self.cfg_scene.itemsBoundingRect(), Qt.KeepAspectRatio)

    def eventFilter(self, source, event):
        """全局事件处理：支持 Ctrl+滚轮缩放"""
        if event.type() == event.Wheel and (event.modifiers() & Qt.ControlModifier):
            delta = event.angleDelta().y()
            if delta > 0:
                self.zoom_in()
            else:
                self.zoom_out()
            return True
        return super().eventFilter(source, event)

    def init_ui(self):
        """初始化用户界面"""

        # 文件选择区域
        file_container = QWidget()
        file_layout = QHBoxLayout(file_container)
        self.file_label = QLabel("源文件路径:")
        self.file_input = QLineEdit()
        self.file_button = QPushButton("浏览")
        file_layout.addWidget(self.file_label)
        file_layout.addWidget(self.file_input)
        file_layout.addWidget(self.file_button)

        # 函数输入区域
        func_container = QWidget()
        func_layout = QHBoxLayout(func_container)
        self.func_label = QLabel("函数名:")
        self.func_input = QLineEdit()
        func_layout.addWidget(self.func_label)
        func_layout.addWidget(self.func_input)

        # 按钮区域
        button_container = QWidget()
        button_layout = QHBoxLayout(button_container)
        self.run_button = QPushButton("生成基本路径集")
        button_layout.addWidget(self.run_button)

        # 输入区域组合
        input_container = QWidget()
        input_layout = QVBoxLayout(input_container)
        input_layout.addWidget(file_container)
        input_layout.addWidget(func_container)
        input_layout.addWidget(button_container)
        input_layout.addStretch(1)  # 添加伸缩空间

        # 输出区域
        output_container = QWidget()
        output_layout = QVBoxLayout(output_container)
        output_layout.addWidget(QLabel("输出结果:"))

        # 创建标签页
        self.tab_widget = QTabWidget()

        # 基本路径输出页面
        path_output_widget = QWidget()
        path_output_layout = QVBoxLayout(path_output_widget)
        self.path_output_area = QTextEdit()
        self.path_output_area.setReadOnly(True)
        path_output_layout.addWidget(self.path_output_area)

        # 邻接矩阵输出页面
        matrix_output_widget = QWidget()
        matrix_output_layout = QVBoxLayout(matrix_output_widget)
        self.matrix_output_area = QTextEdit()
        self.matrix_output_area.setReadOnly(True)
        matrix_output_layout.addWidget(self.matrix_output_area)

        # 添加到标签页
        self.tab_widget.addTab(path_output_widget, "基本路径")
        self.tab_widget.addTab(matrix_output_widget, "邻接矩阵")

        # 添加到输出容器
        output_layout.addWidget(self.tab_widget)

        # CFG图像显示区域
        self.cfg_view = QGraphicsView()
        self.cfg_scene = QGraphicsScene()
        self.cfg_view.setScene(self.cfg_scene)
        self.cfg_view.setMinimumHeight(300)
        self.cfg_view.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.cfg_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.cfg_view.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.cfg_view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)

        # 缩放控制按钮
        zoom_container = QWidget()
        zoom_layout = QHBoxLayout(zoom_container)
        self.zoom_in_button = QPushButton("放大")
        self.zoom_out_button = QPushButton("缩小")
        self.reset_view_button = QPushButton("重置视图")
        zoom_layout.addWidget(self.zoom_in_button)
        zoom_layout.addWidget(self.zoom_out_button)
        zoom_layout.addWidget(self.reset_view_button)

        cfg_container = QWidget()
        cfg_layout = QVBoxLayout(cfg_container)
        cfg_layout.addWidget(QLabel("控制流图 (CFG):"))
        cfg_layout.addWidget(self.cfg_view)
        cfg_layout.addWidget(zoom_container)

        # 创建分割器来管理 CFG 和输出结果
        bottom_splitter = QSplitter(Qt.Vertical)
        bottom_splitter.addWidget(cfg_container)
        bottom_splitter.addWidget(output_container)
        bottom_splitter.setHandleWidth(10)
        bottom_splitter.setChildrenCollapsible(False)

        # 创建主分割器
        main_splitter = QSplitter(Qt.Horizontal)
        main_splitter.addWidget(input_container)
        main_splitter.addWidget(bottom_splitter)
        main_splitter.setHandleWidth(10)
        main_splitter.setChildrenCollapsible(False)
        main_splitter.setStretchFactor(0, 1)
        main_splitter.setStretchFactor(1, 3)

        # 创建滚动区域
        scroll = QScrollArea()
        scroll.setWidget(main_splitter)
        scroll.setWidgetResizable(True)
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        # 设置主布局
        main_layout = QVBoxLayout(self)
        main_layout.addWidget(scroll)

        # 连接信号
        self.file_button.clicked.connect(self.select_file)
        self.run_button.clicked.connect(self.handle_analysis)
        self.zoom_in_button.clicked.connect(self.zoom_in)
        self.zoom_out_button.clicked.connect(self.zoom_out)
        self.reset_view_button.clicked.connect(self.reset_view)

    def select_file(self):
        """打开文件选择对话框"""
        filename, _ = QFileDialog.getOpenFileName(
            self,
            "选择 Python 文件",
            "",
            "*.py;;All Files (*)"
        )
        if filename:
            self.file_input.setText(filename)

    def handle_analysis(self):
        """处理分析请求"""
        file_path = self.file_input.text().strip()
        function_name = self.func_input.text().strip()

        if not file_path or not function_name:
            self.path_output_area.setText("请填写完整的文件路径和函数名！")
            return

        self.path_output_area.setText(f"正在分析函数 {function_name} ...\n\n")

        try:
            # 执行分析
            result = analyze_function(file_path, function_name)

            if result:
                paths, nodes, edges = result

                # 格式化基本路径输出
                output_text = f"函数 {function_name} 的基本路径集{len(paths)}条:\n"
                for i, path in enumerate(paths):
                    path = [node - 1 for node in path]
                    output_text += f"P{i + 1}: {path}\n"

                self.path_output_area.setText(output_text)

                # 格式化邻接矩阵输出
                matrix_text = "CFG邻接矩阵:\n"

                # 获取邻接矩阵大小
                matrix_size = len(nodes) if nodes else 0

                # 重新构建邻接矩阵
                if matrix_size > 0:
                    adj_matrix = [[0] * matrix_size for _ in range(matrix_size)]
                    for src, dst in edges:
                        if src < matrix_size and dst < matrix_size:
                            adj_matrix[src][dst] = 1

                    for row in adj_matrix:
                        matrix_text += f"{row}\n"
                else:
                    matrix_text += "未找到邻接矩阵数据"

                self.matrix_output_area.setText(matrix_text)

                # 显示CFG图像
                cfg_image_path = f"./images/{function_name}_cfg.png"
                self.display_cfg_image(cfg_image_path)

            else:
                self.path_output_area.setText("分析完成，但未找到匹配的函数或发生错误。")

        except Exception as e:
            error_msg = f"分析过程中发生错误：{str(e)}"
            self.path_output_area.setText(error_msg)
            self.show_warning("分析错误", error_msg)

    def display_cfg_image(self, image_path):
        """显示CFG图像"""
        self.cfg_scene.clear()

        # 检查文件是否存在
        if not os.path.exists(image_path):
            self.show_warning("加载CFG图像", f"未能找到控制流图，请检查文件路径：{image_path}")
            return

        # 加载图像
        pixmap = QPixmap(image_path)
        if pixmap.isNull():
            self.show_warning("加载CFG图像", f"无法加载控制流图：{image_path}")
            return

        # 显示图像
        self.cfg_scene.addPixmap(pixmap)

        # 自动调整视图大小
        self.cfg_view.fitInView(self.cfg_scene.itemsBoundingRect(), Qt.KeepAspectRatio)

    def show_warning(self, title, message):
        """显示警告对话框"""
        msg_box = QMessageBox(self)
        msg_box.setIcon(QMessageBox.Warning)
        msg_box.setWindowTitle(title)
        msg_box.setText(message)
        msg_box.exec_()


def run_gui():
    """启动GUI应用程序"""
    app = QApplication(sys.argv)

    # 设置应用程序样式
    app.setStyle("Fusion")

    # 设置全局字体
    font = QFont("Segoe UI", 10)
    app.setFont(font)

    window = PathAnalyzerGUI()
    window.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    run_gui()
